﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace OfflineProgramer
{
    // 烧录器操作所需数据

    
    class ProgramUploadDataOpt
    {
        public readonly byte SEND_BIN_FILE_LEN = 64;  // bin 文件一次发送最大长度
        public enum UPLOAD_STATE
        {
            NULL = 0,
            START_SEND_STRUCT,
            START_SEND_DATA ,
            
        };
        public int fileNum;           // 要发送的文件 或 结构体数量
        public int cureStructId;      // 当前要发送的结构体ID
        public int cureBinId;         // 当前发送的 bin ID

        public UPLOAD_STATE upState;        
        
        public byte sendOrder;        // 发送指令序号
        public UInt32 cureBinSendDataId;  // 当前bin 发送数据序号




    }

    class ProgramSettingData
    {


        // 器件配置
        public Dictionary<byte, string> dicOpType = new Dictionary<byte, string> {
            { 1, "IC固件烧录"},
            { 2, "SPI FLASH烧录"},
            { 3, "ISP 编程"},
        };

        public Dictionary<byte, string> dicManufactorId_IC = new Dictionary<byte, string> {
            { 1, "ST"},
            { 2, "AT"},
            { 3, "HR"},
            { 4, "N32"},
            { 5, "HC"},
            { 6, "GD32"},
            { 7, "SW"},
            { 8, "YWS"},
            { 9, "NRF"},

        };


        public Dictionary<byte, string> dicManufactorId_Flash = new Dictionary<byte, string> {
            { 1, "WINDBOND"},
            { 2, "OTHER"},
        };



        public Dictionary<UInt32, string> dicChipIDCODE_ST = new Dictionary<UInt32, string> {
            { 1, "STM32F1XX"},
            { 2, "STM32F4XX"},
            { 3, "STM32F0XX_1024"},
            { 4, "STM32L0XX"},
            { 5, "STM32F4XX_2048"},
            { 6, "STM32L4XX_128"},
            { 7, "STM32L4XX_256"},
            { 8, "STM32L4XX_512"},
            { 9, "STM32L4XX_1024"},
            { 10, "STM32G0Bx_128"},
            { 11, "STM32G0Bx_256"},
            { 12, "STM32G0Bx_512"},
            { 13, "STM32G4xx_128"},
            { 14, "STM32G4xx_256"},
            { 15, "STM32G4xx_512"},
            { 16, "STM32G43x_4x_128"},
            { 17, "STM32U5xx_1M_0800"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_AT = new Dictionary<UInt32, string> {
            { 1, "AT32F4XX"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_N32 = new Dictionary<UInt32, string> {
            { 1, "N32L40XX"},
            { 2, "N32G45X"},
            { 3, "N32G003F5"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_HC = new Dictionary<UInt32, string> {
            { 1, "HC32L17XX"},
        };
        public Dictionary<UInt32, string> dicChipIDCODE_GD = new Dictionary<UInt32, string> {
            { 1, "GD32F10X_128"},
            { 2, "GD32F10X_512"},
            { 3, "GD32F10X_1024"},
            { 4, "GD32F30X_512"},
            { 5, "GD32F30X_1024"},
        }; 
        public Dictionary<UInt32, string> dicChipIDCODE_SW = new Dictionary<UInt32, string> {
            { 1, "SWM341xE"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_YWS = new Dictionary<UInt32, string> {
            { 1, "YWS32F403xE"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_NRF = new Dictionary<UInt32, string> {
            { 1, "NRF52x"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_HR = new Dictionary<UInt32, string> {
            { 1, "HR8P506x"},
            { 2, "HR8P508x"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_Flash_W = new Dictionary<UInt32, string> {
            { 1, "W25Q32"},
            { 2, "W25Q64"},
        };

        public Dictionary<UInt32, string> dicChipIDCODE_Flash_E = new Dictionary<UInt32, string> {
            { 1, "E25Q32"},
            { 2, "E25Q64"},
        };


        // 固件配置

        // ProgSpeed 编程速度
        public Dictionary<UInt32, string> dicProgSpeed = new Dictionary<UInt32, string> {
            { 0, "高速编程"},
            { 1, "中速编程"},
        };

        // EraseType 擦除方式
        public Dictionary<UInt32, string> dicEraseType = new Dictionary<UInt32, string> {
            { 0, "全片擦除"},
            { 1, "扇区擦除"},
        };

        // OutVoltage 输出电压
        public Dictionary<UInt32, string> dicOutVoltage = new Dictionary<UInt32, string> {
            { 0, "3.3V输出供电"},
            { 1, "5V输出供电"},
        };


        public List<Dictionary<UInt32, string>> chipIdCodeList_IC = new List<Dictionary<uint, string>>();
        public List<Dictionary<UInt32, string>> chipIdCodeList_Flash = new List<Dictionary<uint, string>>();

        public List<Dictionary<byte, string>> chipManufactorIdList = new List<Dictionary<byte, string>>();


        public ProgramSettingData()
        {
            chipIdCodeList_IC.Add(dicChipIDCODE_ST);
            chipIdCodeList_IC.Add(dicChipIDCODE_AT);
            chipIdCodeList_IC.Add(dicChipIDCODE_HR);
            chipIdCodeList_IC.Add(dicChipIDCODE_N32);
            chipIdCodeList_IC.Add(dicChipIDCODE_HC);
            chipIdCodeList_IC.Add(dicChipIDCODE_GD);
            chipIdCodeList_IC.Add(dicChipIDCODE_SW);
            chipIdCodeList_IC.Add(dicChipIDCODE_YWS);
            chipIdCodeList_IC.Add(dicChipIDCODE_NRF);
            
            chipIdCodeList_Flash.Add(dicChipIDCODE_Flash_W);
            chipIdCodeList_Flash.Add(dicChipIDCODE_Flash_E);

            chipManufactorIdList.Add(dicManufactorId_IC);
            chipManufactorIdList.Add(dicManufactorId_Flash);

        }


    }

    // Bin文件信息

    //  Bin文件信息 以及 配置信息
    class ProgramFileOperation
    {
        private byte structStartFlag;          // 烧录文件结构标志:0x55
        private byte flashOpType;              // 固件标志： 1：SWD 烧录  2：SPI烧录 3：串口IAP烧录

        private UInt32 fileLen;                // 文件长度
        private UInt32 fileCrc;                // CRC32校验
        private UInt32 fileAddr;               // BIN文件在SPI FLASH中存储起始地址
        private UInt32 flashAddr;              // 目标烧录起始地址
        private byte manufactorId;             // 厂商ID
        private UInt32 chipIDCODE;             // 芯片系列ID IDCODE
        private byte flash_opt_bit;           // 烧录操作设置
                                              /*
                                              // 烧录操作设置
                                              uint8_t erase         : 1;  // 是否擦除
                                              uint8_t check         : 1;  // 是否校验
                                              uint8_t speed         : 1;  // 烧录速度
                                              uint8_t isAuto        : 1;  // 是否自动烧录
                                              uint8_t isReset       : 1;  // 是否自动重启
                                              uint8_t voltage       : 1;  // 输出电压选择
                                              uint8_t protect       : 1;  // 读写保护
                                              uint8_t burnTimes     : 1;  // 关闭开启烧录次数

                                              */

        private UInt16 burnTimes;           // 烧录次数    
        private byte[] settingByte = new byte[20];         // 配置字用 或保留
        private UInt16 keepByte;            // 保留字节
       
        private byte[] fileNameStr = new byte[20];      // 文件名
        private byte chk;                  // 结构体数据校验
        private byte structEndFlag;        // 烧录文件结构标志:0xAA      

        private byte[] fileBinData;       // = new byte[1024*1024];  //1M 文件大小

        private UInt32 fileAddrNext;               // 下一个BIN文件在SPI FLASH中存储起始地址

        private static byte[] dataFileStructByte = new byte[74];

        public byte StructStartFlag { get => structStartFlag; set => structStartFlag = value; }
        public byte FlashOpType { get => flashOpType; set => flashOpType = value; }
        public uint FileLen { get => fileLen; set => fileLen = value; }
        public uint FileCrc { get => fileCrc; set => fileCrc = value; }
        public uint FileAddr { get => fileAddr; set => fileAddr = value; }
        public uint FlashAddr { get => flashAddr; set => flashAddr = value; }
        public byte ManufactorId { get => manufactorId; set => manufactorId = value; }
        public uint ChipIDCODE { get => chipIDCODE; set => chipIDCODE = value; }
        public byte Flash_opt_bit { get => flash_opt_bit; set => flash_opt_bit = value; }
        public ushort BurnTimes { get => burnTimes; set => burnTimes = value; }
        public ushort KeepByte { get => keepByte; set => keepByte = value; }
        public byte[] FileNameStr { get => fileNameStr; set => fileNameStr = value; }
        public byte Chk { get => chk; set => chk = value; }
        public byte StructEndFlag { get => structEndFlag; set => structEndFlag = value; }
        public byte[] FileBinData { get => fileBinData; set => fileBinData = value; }
        public byte[] SettingByte { get => settingByte; set => settingByte = value; }
        public uint FileAddrNext { get => fileAddrNext; set => fileAddrNext = value; }

        private byte[] Get16BitData(UInt16 data)
        {
            byte[] ret = new byte[2];

            ret[1] = (byte)((data>>8) & 0xff);
            ret[0] = (byte)(data & 0xff);
            return ret;
        }
        private byte[] Get32BitData(UInt32 data)
        {
            byte[] ret = new byte[4];

            
            ret[3] = (byte)((data >> 24) & 0xff);
            ret[2] = (byte)((data >> 16) & 0xff);
            ret[1] = (byte)((data >> 8) & 0xff);
            ret[0] = (byte)(data & 0xff);

            return ret;
        }


        // 将数据打包到 dataFileStructByte中
        public byte[] GetPackDataToByte()
        {
            structStartFlag = 0x55;
            structEndFlag = 0xAA;

            dataFileStructByte[0] = structStartFlag;
            dataFileStructByte[1] = flashOpType;

            Buffer.BlockCopy(Get32BitData(fileLen), 0, dataFileStructByte, 2, 4);

            Buffer.BlockCopy(Get32BitData(fileCrc), 0, dataFileStructByte, 6, 4);

            Buffer.BlockCopy(Get32BitData(fileAddr), 0, dataFileStructByte, 10, 4);

            Buffer.BlockCopy(Get32BitData(flashAddr), 0, dataFileStructByte, 14, 4);

            dataFileStructByte[18] = manufactorId;

            Buffer.BlockCopy(Get32BitData(chipIDCODE), 0, dataFileStructByte, 19, 4);

            dataFileStructByte[23] = flash_opt_bit;

            Buffer.BlockCopy(Get32BitData(burnTimes), 0, dataFileStructByte, 24, 4);

            Buffer.BlockCopy(settingByte, 0, dataFileStructByte, 28, 20);

            Buffer.BlockCopy(Get32BitData(keepByte), 0, dataFileStructByte, 48, 4);

            Buffer.BlockCopy(fileNameStr, 0, dataFileStructByte, 52, fileNameStr.Length);

            chk = ProgramFrame.GetCheckValue(dataFileStructByte, 73);
            dataFileStructByte[72] = chk;

            // 校验

            dataFileStructByte[73] = StructEndFlag;

            return dataFileStructByte;
        }
        // 将byte字节解开到数据结构中
        void UnPackByteToData()
        {

        }

    }


    // 帧打包 解包处理
    class ProgramFrame
    {
        readonly static byte[] FRAME_HEAD = new byte[] { 0x55, 0x00, 0xaa };     // 帧头


        readonly static byte FRAME_LEN_POS = 4;   //数据长度所在位置


        public static byte[] sendMsgBuf;
        public static List<byte> tempMsgBuf;
        public static Queue<byte[]> rxFrameQueue = new Queue<byte[]>();  // = new List<List<byte>>();

        public static List<byte> tempRecvMsgBuf = new List<byte>();// =new List<byte>();  //接收缓存

        /*

          命令头 + 命令字 + 数据长度 + 板卡编号 + 数据路径 +数 据 1 + 数 据 2 + … … + 数 据 N + 校 验 码

         */
        static byte order = 0;
        static byte boardId;       // 板卡序号 :前4bit为底板分配的同种板卡的静态地址，未配置时刻静态地址为0，最大可表示有相同板卡类型15个，后4bit节为板卡类型。
        static byte boardDataPath; // 板卡数据路径 :前4bit为s_addr，后4bit为t_addr。
        static byte dataLen;       // 数据长度 :数据长度后面数据的个数，不包含校验码。
        static byte checkValue;    // 校验值 :从命令头开始，至校验码之前一个字节为止，依次相异或的运算结果取反。

        public enum PRO_FRAM_CMD
        {
            SETTING_SLAVE_ADDR_ASK = 0x60,
            SETTING_SLAVE_ADDR_ANS = 0x61,

            CMD_CARD_INFO_ASK = 0x62,                               // 烧录卡从模块版本信息获取
            CMD_CARD_INFO_ANS = 0x63,

            QUERY_SLAVE_STATE_ASK = 0x64,
            QUERY_SLAVE_STATE_ANS = 0x65,
            
            SEND_OPT_CMD_ASK = 0x66,
            SEND_OPT_CMD_ANS = 0x67,

            TRANS_DATA_STRUCT_CMD_ASK = 0x68,
            TRANS_DATA_STRUCT_CMD_ANS = 0x69,

            TRANS_DATA_CMD_ASK = 0x6A,
            TRANS_DATA_CMD_ANS = 0x6B,

            TRANS_DATA_FINISH_CMD_ASK = 0x6C,
            TRANS_DATA_FINISH_CMD_ANS = 0x6D,

        };

        // 计算校验值
        public static byte GetCheckValue(byte[] data, int len)
        {
            byte ret = 0;
            for (int i = 0; i < len; i++)
            {
                ret ^= data[i];
            }
            return (byte)~ret;
        }

        // 添加校验
        private static void PackAddSum()
        {
            byte len = (byte)(tempMsgBuf.Count - 5);
            tempMsgBuf[FRAME_LEN_POS] = len;
            byte chk = GetCheckValue(tempMsgBuf.ToArray(), tempMsgBuf.Count);
            tempMsgBuf.Add(chk);
            sendMsgBuf = new byte[tempMsgBuf.Count];
            tempMsgBuf.CopyTo(sendMsgBuf);
        }

        // 根据指令打包头
        private static void PackHeadByCMD(PRO_FRAM_CMD CMD)
        {
            tempMsgBuf = new List<byte>();
            tempMsgBuf.AddRange(FRAME_HEAD);
            tempMsgBuf.Add((byte)CMD);
            tempMsgBuf.Add((byte)dataLen);
            tempMsgBuf.Add(boardId);
            tempMsgBuf.Add(boardDataPath);
           // tempMsgBuf.Add(0);  // 帧序号

        }

        private static void PackAddData(byte[] data)
        {
            tempMsgBuf.AddRange(data);
        }

        private static void PackAddData(byte data)
        {
            tempMsgBuf.Add(data);
        }

        private static void PackAddData(UInt32 data)
        {
            tempMsgBuf.Add((byte)((data>>24)&0xff));
            tempMsgBuf.Add((byte)((data >> 16) & 0xff));
            tempMsgBuf.Add((byte)((data >> 8) & 0xff));
            tempMsgBuf.Add((byte)(data & 0xff));
        }

        //1、烧录卡从模块地址配置（下行 命令字 =0x40）
        public static void Pack_SettingSlaveAddrCMD(byte addr)
        {
            PackHeadByCMD(PRO_FRAM_CMD.SETTING_SLAVE_ADDR_ASK);
            PackAddData(0);
            PackAddData(addr);
            PackAddSum();

        }

        //3、查询模块状态命令（上行 命令字 =0x42）
        public static void Pack_QuerySlaveStateCMD(byte type, byte addr)
        {
            PackHeadByCMD(PRO_FRAM_CMD.QUERY_SLAVE_STATE_ASK);
            PackAddData(0);
            PackAddData(addr);
            PackAddSum();

        }

        //5、烧录卡烧录目标板指令（下行 命令字 =0x44）
        public static void Pack_SendOptCMD(byte opt, byte id,byte optCmd,byte fileId)
        {
            PackHeadByCMD(PRO_FRAM_CMD.SEND_OPT_CMD_ASK);
            PackAddData(opt);// 0为广播，所有模块开始执行烧录。1为指定模块开始烧录。
            PackAddData(id);// 从模块的地址。广播时，模块地址无效。
            PackAddData(optCmd);// 0：为按照配置烧录目标，1为擦除目标,,2为重启目标(SPI FLASH操作时，该值无效)。
            PackAddData(fileId);// 指定烧录文件ID。
            PackAddSum();
        }

        //7、烧录卡传输配置指令（下行 命令字 = 0x46）
        public static void Pack_TransDataStructCMD(byte order,byte id, byte[] dataStructBuf)
        {
            PackHeadByCMD(PRO_FRAM_CMD.TRANS_DATA_STRUCT_CMD_ASK);
   
            PackAddData(order);
            PackAddData(id);
            PackAddData(dataStructBuf);
            PackAddSum();
        }

        //9、烧录卡传输文件指令（下行 命令字 =0x48）
        public static void Pack_TransDataCMD(byte order, byte id, UInt32 dataOrder,  byte dataLen, byte[] dataBuf)
        {
            PackHeadByCMD(PRO_FRAM_CMD.TRANS_DATA_CMD_ASK);
            PackAddData(order);
            PackAddData(id);
            PackAddData(dataOrder);
            PackAddData(0);
            PackAddData(dataLen);
            PackAddData(dataBuf);
            PackAddSum();

        }


        //11、烧录卡传输文件完毕（下行 命令字 =0x4A）
        public static void Pack_TransDataFinishCMD(byte id)
        {
            PackHeadByCMD(PRO_FRAM_CMD.TRANS_DATA_FINISH_CMD_ASK);
            PackAddData(id);
            PackAddSum();
        }

        // rx 数据读取到列表中
        public static void RxDataReadIntoList(byte[] buf)
        {

 
            tempRecvMsgBuf.AddRange(buf);
                                       //1.缓存数据
            while (tempRecvMsgBuf.Count >= 4) //
            {

                if (tempRecvMsgBuf[0] == 0X55) //找到帧头
                {
                    int len = tempRecvMsgBuf[4];
                    if (tempRecvMsgBuf.Count < len + 6) //数据区尚未接收完整，
                    {
                        break;//跳出接收函数后之后继续接收数据
                    }
                    byte[] chk = new byte[len + 6];
                    tempRecvMsgBuf.CopyTo(0, chk, 0, len + 6);//

                    byte cc = GetCheckValue(chk, chk.Length - 1);

                    if ( cc == chk[chk.Length-1])
                    {
                        RecvCmdOpt(chk);
                        tempRecvMsgBuf.RemoveRange(0, len + 6);
                        continue;

                    }


                    tempRecvMsgBuf.RemoveRange(0, len + 6);
                }
                else
                {
                    tempRecvMsgBuf.RemoveAt(0);
                }
            }



        }
        public delegate void FrameCmdRecv(byte[] cmdFrame);
        public static event FrameCmdRecv FrameCmdRecvDada;
            

        // 解析帧后根据指令进行操作
        public static void RecvCmdOpt(byte[] cmdFrame)
        {
             FrameCmdRecvDada.Invoke(cmdFrame);



            /*
            switch ((PRO_FRAM_CMD)cmdFrame[4])
            {
                case PRO_FRAM_CMD.SETTING_SLAVE_ADDR_ANS:

                    break;
                case PRO_FRAM_CMD.QUERY_SLAVE_STATE_ANS:
                    break;
                case PRO_FRAM_CMD.SEND_OPT_CMD_ANS:
                    break;
                case PRO_FRAM_CMD.TRANS_DATA_STRUCT_CMD_ANS:
                    break;
                case PRO_FRAM_CMD.TRANS_DATA_CMD_ANS:
                    break;
                case PRO_FRAM_CMD.TRANS_DATA_FINISH_CMD_ANS:
                    break;

            }
            */


        }

    }



}
